'''
Created on 23/12/2009
Atualizado em 12/02/2011
@author: vinicius
'''

from funcoes import valorMinimo,norma
from padrao import Padrao

class KMeans():
    
    #Construtor
    def __init__(self,numClusters,treinamento):
        self.treinamento = treinamento
        self.clusters = [None]*numClusters
        self.centroides  = [None]*numClusters
        self.varClusters = [None]*numClusters
        self.iteracoes = 0
    
    
    #Rotina principal
    def executar(self):
        self.initClusters()
        self.computeGrupos()
        while True:
            self.computeCentroides()
            self.computeGrupos()
            if self.computeCriterioParada() == True:
                break
            self.iteracoes+=1
    
    
    #Inicializa os clusters com centros aleatorios
    def initClusters(self):
        for i in range(len(self.clusters)):
            cluster = Cluster()
            self.clusters[i] = cluster
            centroideInicial = self.treinamento[i]
            cluster.padroes.append(centroideInicial)
            cluster.centroide = centroideInicial

          
    #Associa os padroes aos grupos de acordo com similaridade  
    def computeGrupos(self):
        clustersTemp = [None]*len(self.clusters)
        for i in range(len(self.clusters)):
            c = Cluster()
            clustersTemp[i] = c
            clustersTemp[i].centroide = self.clusters[i].centroide
        for padrao in self.treinamento:
            distanciasPadraoGrupo = []
            for cluster in self.clusters:
                distanciasPadraoGrupo.append(norma(padrao.atributos,cluster.centroide.atributos))
            indice = valorMinimo(distanciasPadraoGrupo)
            clustersTemp[indice].padroes.append(padrao)
        for i in range(len(self.clusters)):
            self.clusters[i] = clustersTemp[i]
            
    #Recalcula os centros
    def computeCentroides(self):
        for k in range(len(self.clusters)):
            atributos = []
            media = 0.0
            cluster = self.clusters[k]
            for i in range(len(cluster.centroide.atributos)):
                for padrao in cluster.padroes:
                    media += padrao.atributos[i]
                denominador = len(cluster.padroes)
                media /= denominador
                atributos.append(round(media,3))
            novoCentroide = Padrao()
            novoCentroide.atributos = atributos
            self.centroides[k] = self.clusters[k].centroide   
            self.clusters[k].centroide = novoCentroide
            
    #Computa o criterio de parada 
    def computeCriterioParada(self):
        parada = True
        for i in range(len(self.clusters)):
            convergiu = False
            centroideCalculado = self.clusters[i].centroide
            centroideAtual = self.centroides[i]
            if centroideAtual.atributos == centroideCalculado.atributos:
                convergiu = True
            parada = parada and convergiu
        return parada

#Classe de representacao dos grupos
class Cluster():
    def __init__(self):
        self.padroes = []
        self.centroide = None